/*
 * Intermud finger server
 * Original author: Huthar@Portals
 * Rewritten: Blackthorn@Genocide (10/31/92)
 * TMI-2 conversion: Buddha@tmi-2 (11/5/92)
 * 93-08-14 Grendel@tmi-2 Updated to work with dns
 */

#include <net/daemons.h>
#include <net/services.h>
#include <net/config.h>
#include <net/dns.h>

#define log(x) log_file("FS", x)

mapping requests;

// The interface to the mudlib
void remote_finger(object source, string user, string mud);
private
void udp_finger(object source, string user, string mud);
private
void tcp_finger(object source, string user, string mud);

// The inetd functions
void service_request(int id, mixed *parms);
void read_callback(int id, string msg);
void close_callback(int id);
void timeout(int id);

void create()
{
    seteuid(ROOT_UID);
    requests = ([]);
}

// this is called by the finger command.  it works out which type of protocol
// to use, then acts appropriatley
void remote_finger(object source, string user, string mud)
{
    //mapping minfo;
    int msvc;

    if (!DNS_MASTER->query_mud_info(mud))
    {
        tell_object(source, "fingerd: no mud with that name presently active\n");
        return;
    }
    msvc = (int)DNS_MASTER->query_service_method(mud, "finger");

#if PREF_FINGER & SVC_TCP
    if (msvc & SVC_TCP)
        tcp_finger(source, user, mud);
    else if (msvc & SVC_UDP)
        udp_finger(source, user, mud);
#elif PREF_FINGER & SVC_UDP
    if (msvc & SVC_UDP)
        udp_finger(source, user, mud);
    else if (msvc & SVC_TCP)
        tcp_finger(source, user, mud);
#else
    if (0)
        ; //force the following else to be taken
#endif
    else
        tell_object(source, "fingerd: cannot determine protocol\n");
}

private
void udp_finger(object source, string user, string mud)
{
    if (!DNS_MASTER->query_mud_info(mud))
    {
        // this is bad, you had to have a service entry to get here
        tell_object(source, "fingerd: error: unknown mud has service entry\n");
        return;
    }
    if (user != "")
        (AUX_PATH + "gfinger_q")->send_gfinger_q(mud, user, source);
    else
        (AUX_PATH + "rwho_q")->send_rwho_q(mud, source, 1);
    tell_object(source, "Finger on its way.  May take some time.\n");
    return;
}

private
void tcp_finger(object source, string user, string mud)
{
    int id;

    id = INETD->open_service(mud, "finger", ({user}));
    if (id < 0)
    {
        tell_object(source, "Remote mud does not exist.\n");
        return;
    }
    requests[id] = ({source, user, mud});
    call_out("timeout", SERVICE_TIMEOUT, id);
}

/* The inetd daemon interface */

/* This is called by the inet daemon when it receives an incoming
 * finger request
 */
void service_request(int id, mixed *parms)
{
    string *lines;
    int i;

    if (!parms || !sizeof(parms) || !parms[0])
    {
        lines = explode((string)FINGER_D->finger_all(), "\n");
        INETD->write_socket(id, "\n");
        for (i = 0; i < sizeof(lines); i++)
            INETD->write_socket(id, lines[i] + "\n");
    }
    else
    {
        if (stringp(parms[0]))
        {
            lines = explode((string)FINGER_D->finger_user(parms[0]), "\n");
            INETD->write_socket(id, "\n");
            for (i = 0; i < sizeof(lines); i++)
                INETD->write_socket(id, lines[i] + "\n");
        }
    }
    INETD->close_socket(id);
}

void read_callback(int id, string msg)
{
    if (!msg)
        return;
    tell_object(requests[id][0], msg);
}

void close_callback(int id)
{
    map_delete(requests, id);
}

void timeout(int id)
{
    if (!requests[id])
        return;
    tell_object(requests[id][0], "Remote finger connection timed out.\n");
    INETD->close_socket(id);
    map_delete(requests, id);
}
